﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MessageSystem.Managed.Interface;

namespace MessageSystem.Managed.Rpc
{
    public class RpcPermanentDomain:RpcDomain
    {
        public Action OnConnected { get; set; }
        public Action OnLosted { get; set; }
        public Action OnTryConnect { get; set; }

        private IMessageSystem _messagesystem;
        private bool _connecting;
        private int _tryTimes;
        private int _delaySeconds;
        private DateTime _lastConnectTime;
        private int      _lastTryTimes;
        private List<IMessage> _allMessages;

        public RpcPermanentDomain(RpcAddress address, IMessageSystem Ms,int tryTimes,int delaySeconds)
            :base(null,address)
        {
            _messagesystem = Ms;
            _connecting = false;
            _tryTimes = tryTimes;
            _delaySeconds = delaySeconds;
            _lastTryTimes = _tryTimes;
            _allMessages = new List<IMessage>();
        }

        public void Update()
        {
            if (_channel == null && !_connecting)
            {
                if (_lastTryTimes > 0)
                {
                    // 没有连接而且不再尝试连接中，发起连接
                    TryConnect();
                }
                else
                {
                    if ((DateTime.Now - _lastConnectTime).TotalSeconds > _delaySeconds)
                    {
                        _connecting = false;
                        _lastTryTimes = _tryTimes;
                        TryConnect();
                    }
                }
            }
        }

        private void TryConnect()
        {
            if (OnTryConnect != null)
                OnTryConnect();

            _connecting = true;
            _lastConnectTime = DateTime.Now;
            _lastTryTimes -= 1;
            _messagesystem.ConnectRemoteSystem(Address.Ip, Address.Port, delegate(IMessageChannel mc)
            {
                OnConnectSuccess(mc);
            }, OnConnectFail);
        }

        private void OnConnectSuccess(IMessageChannel mc)
        {
            _connecting = false;
            _channel = mc;
            _channel.Open(this);
            if (OnConnected != null)
                OnConnected();

            // flush messages
            foreach (IMessage msg in _allMessages)
            {
                Invoke(msg, msg.Flags, msg.Sessionid, msg.OpCode);
            }
        }

        private void OnConnectFail()
        {
            _connecting = false;
        }

        public override void OnLost()
        {
            _channel = null;
            base.OnLost();

            if (null != OnDomainLost)
            {
                OnDomainLost(this);
            }
        }

        internal override void Invoke(IMessage msg, UInt16 flags, int sessionid, Int32 OpCode)
        {
            if (null == _channel)
            {
                msg.Flags = flags;
                msg.Sessionid = sessionid;
                msg.OpCode = OpCode;
                _allMessages.Add(msg);
            }
            else
            {
                base.Invoke(msg, flags, sessionid, OpCode);
            }
        }
    }
}
